# Copyright (c) SandboxAQ. All rights reserved.
# SPDX-License-Identifier: AGPL-3.0-only

load("@rules_rust//bindgen:bindgen.bzl", "rust_bindgen_library")
load("@rules_rust//rust:defs.bzl", "rust_shared_library", "rust_static_library")
load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("//common/rules/rust/bindgen:rules.bzl", "bindgen_add_prefix_link_name")
load("@com_sandboxquantum_bartleby//:rules.bzl", "bartleby")
load("//common/rules/mkdocs:rules.bzl", "mkdocs_tree")
load(":rules.bzl", "sandwich_variant")

# Source files of Sandwich.
_SANDWICH_SRCS = [
    "//rust/error",
    "//rust/experimental",
    "//rust/experimental/turbo",
    "//rust/experimental/turbo/io",
    "//rust/experimental/turbo/protocol",
    "//rust/experimental/turbo/support",
    "//rust/ffi",
    "//rust/implementation",
    "//rust/implementation/openssl3",
    "//rust/implementation/ossl",
    "//rust/implementation/ossl/boringssl",
    "//rust/implementation/ossl/openssl1_1_1",
    "//rust/io",
    "//rust/io/helpers",
    "//rust/io/listener",
    "//rust/support",
    "//rust/tunnel",
    "//rust/tunnel/ffi",
    "//rust/tunnel/tls",
    "lib.rs",
]

# Rust dependencies for unit tests.
_SANDWICH_RUNFILES_DEPS = [
    "@rules_rust//tools/runfiles",
]

_TRACING_DEPS = [
    "@crate_index//:opentelemetry",
    "@crate_index//:opentelemetry_api",
    "@crate_index//:futures-util",
]

# Protobuf dependencies for Sandwich.
_SANDWICH_PROTOBUF_DEPS = [
    "//proto:sandwich_rust_proto",
    "//proto/api/v1:api_rust_proto",
    "@crate_index//:protobuf",
] + _TRACING_DEPS

# Rust dependencies for Turbo transport.
_SANDWICH_TURBO_DEPS = [
    "@crate_index//:byteorder",
    "@crate_index//:log",
    "@crate_index//:polling",
    "@crate_index//:rand_core",
    "@crate_index//:socket2",
]

sandwich_variant(
    name = "naked",
    srcs = _SANDWICH_SRCS,
    crate_features = [],
    rustc_flags = [
        "-W",
        "missing_docs",
        "-A",
        "dead_code",
        "-A",
        "unused_imports",
        "-A",
        "unused_macros",
    ],
    visibility = ["//visibility:public"],
    deps = _SANDWICH_PROTOBUF_DEPS,
)

##########################################
### BEGIN OpenSSL 1.1.1 related rules  ###
###                                    ###
### The following rules enable the     ###
### support of OpenSSL in Sandwich.    ###
##########################################

_OPENSSL1_1_1_LINK_PREFIX = "__private_ossl1_1_1_"

# OpenSSL 1.1.1, prefixed with Bartleby.
bartleby(
    name = "openssl1_1_1_bartleby",
    srcs = ["//vendor/github.com/open-quantum-safe/liboqs-openssl:openssl"],
    prefix = _OPENSSL1_1_1_LINK_PREFIX,
)

# C library to guide Rust-bindgen for generating OpenSSL 1.1.1 bindings.
cc_library(
    name = "openssl1_1_1_bindgen_library",
    hdrs = [
        "//rust/implementation/ossl/openssl1_1_1:bindgen",
    ],
    deps = [
        ":openssl1_1_1_bartleby",
    ],
)

# OpenSSL 1.1.1 bindings.
rust_bindgen_library(
    name = "openssl1_1_1_bindgen",
    bindgen_flags = bindgen_add_prefix_link_name(_OPENSSL1_1_1_LINK_PREFIX),
    cc_lib = ":openssl1_1_1_bindgen_library",
    clang_flags = select({
        "@platforms//os:ios": [
            "-target",
            "arm64-ios",
        ],
        "//conditions:default": [],
    }),
    crate_name = "openssl1_1_1",
    header = "//rust/implementation/ossl/openssl1_1_1:bindgen",
    rustc_flags = [
        "-A",
        "non-camel-case-types",
        "-A",
        "non-upper-case-globals",
        "-A",
        "non_snake_case",
        "-A",
        "improper_ctypes",
    ],
)

sandwich_variant(
    name = "openssl1_1_1",
    srcs = _SANDWICH_SRCS,
    crate_features = ["openssl1_1_1"],
    generate_ffi = True,
    rustc_flags = [
        "-W",
        "missing_docs",
    ],
    visibility = ["//visibility:public"],
    deps = [":openssl1_1_1_bindgen"] + _SANDWICH_PROTOBUF_DEPS,
)

rust_static_library(
    name = "sandwich_openssl1_1_1_ffi_static",
    srcs = _SANDWICH_SRCS,
    crate_features = [
        "ffi",
        "openssl1_1_1",
        "tunnel",
    ],
    crate_name = "sandwich_openssl1_1_1",
    proc_macro_deps = ["@crate_index//:async-trait"],
    visibility = ["//visibility:public"],
    deps = [":openssl1_1_1_bindgen"] + _SANDWICH_PROTOBUF_DEPS,
)

rust_shared_library(
    name = "sandwich_openssl1_1_1_ffi_shared",
    srcs = _SANDWICH_SRCS,
    crate_features = [
        "ffi",
        "openssl1_1_1",
        "tunnel",
    ],
    crate_name = "sandwich_openssl1_1_1",
    proc_macro_deps = ["@crate_index//:async-trait"],
    visibility = ["//visibility:public"],
    deps = [":openssl1_1_1_bindgen"] + _SANDWICH_PROTOBUF_DEPS,
)

######################################
### END OpenSSL 1.1.1 related rules###
######################################

######################################
### BEGIN BoringSSL related rules  ###
###                                ###
### The following rules enable the ###
### support of BoringSSL           ###
### in Sandwich.                   ###
######################################

_BORINGSSL_LINK_PREFIX = "__private_boringssl_"

# BoringSSL, prefixed with Bartleby.
bartleby(
    name = "boringssl_bartleby",
    srcs = ["//vendor/github.com/open-quantum-safe/boringssl"],
    prefix = _BORINGSSL_LINK_PREFIX,
)

# C library to guide Rust-bindgen for generating BoringSSL bindings.
cc_library(
    name = "boringssl_bindgen_library",
    hdrs = [
        "//rust/implementation/ossl/boringssl:bindgen",
    ],
    deps = [
        ":boringssl_bartleby",
    ],
)

# BoringSSL bindings.
rust_bindgen_library(
    name = "boringssl_bindgen",
    bindgen_flags = bindgen_add_prefix_link_name(_BORINGSSL_LINK_PREFIX),
    cc_lib = ":boringssl_bindgen_library",
    clang_flags = select({
        # This flag is needed for the CircleCI macos job to cross-compile
        # Sandwich to Rust from an x86_64 host, because `bindgen` does not
        # officially support iOS and aarch64.
        "@platforms//os:ios": [
            "-target",
            "arm64-ios",
        ],
        "//conditions:default": [],
    }),
    crate_name = "boringssl",
    header = "//rust/implementation/ossl/boringssl:bindgen",
    rustc_flags = [
        "-A",
        "non-camel-case-types",
        "-A",
        "non-upper-case-globals",
        "-A",
        "non_snake_case",
        "-A",
        "improper_ctypes",
    ],
)

sandwich_variant(
    name = "boringssl",
    srcs = _SANDWICH_SRCS,
    crate_features = ["boringssl"],
    generate_ffi = True,
    rustc_flags = [
        "-W",
        "missing_docs",
    ],
    visibility = ["//visibility:public"],
    deps = [":boringssl_bindgen"] + _SANDWICH_PROTOBUF_DEPS,
)

rust_static_library(
    name = "sandwich_boringssl_ffi_static",
    srcs = _SANDWICH_SRCS,
    crate_features = [
        "boringssl",
        "ffi",
        "tunnel",
    ],
    crate_name = "sandwich_boringssl",
    proc_macro_deps = ["@crate_index//:async-trait"],
    visibility = ["//visibility:public"],
    deps = [":boringssl_bindgen"] + _SANDWICH_PROTOBUF_DEPS,
)

rust_shared_library(
    name = "sandwich_boringssl_ffi_shared",
    srcs = _SANDWICH_SRCS,
    crate_features = [
        "ffi",
        "boringssl",
        "tunnel",
    ],
    crate_name = "sandwich_boringssl",
    proc_macro_deps = ["@crate_index//:async-trait"],
    visibility = ["//visibility:public"],
    deps = [":boringssl_bindgen"] + _SANDWICH_PROTOBUF_DEPS,
)

######################################
### END BoringSSL related rules    ###
######################################

##########################################
### BEGIN OpenSSL 3 related rules      ###
###                                    ###
### The following rules enable the     ###
### support of OpenSSL in Sandwich.    ###
##########################################

_OPENSSL3_LINK_PREFIX = "__private_ossl3_"

# OpenSSL 3, prefixed with Bartleby.
bartleby(
    name = "openssl3_bartleby",
    srcs = [
        "//vendor/github.com/open-quantum-safe/liboqs",
        "//vendor/github.com/open-quantum-safe/oqs-provider",
        "//vendor/github.com/openssl/openssl",
    ],
    prefix = _OPENSSL3_LINK_PREFIX,
)

# C library to guide Rust-bindgen for generating OpenSSL 3 bindings.
cc_library(
    name = "openssl3_bindgen_library",
    hdrs = [
        "//rust/implementation/openssl3:bindgen",
    ],
    deps = [
        ":openssl3_bartleby",
    ],
)

# OpenSSL 3 bindings.
rust_bindgen_library(
    name = "openssl3_bindgen",
    bindgen_flags = bindgen_add_prefix_link_name(_OPENSSL3_LINK_PREFIX),
    cc_lib = ":openssl3_bindgen_library",
    clang_flags = select({
        "@platforms//os:ios": [
            "-target",
            "arm64-ios",
        ],
        "//conditions:default": [],
    }),
    crate_name = "openssl3",
    header = "//rust/implementation/openssl3:bindgen",
    rustc_flags = [
        "-A",
        "non-camel-case-types",
        "-A",
        "non-upper-case-globals",
        "-A",
        "non_snake_case",
        "-A",
        "improper_ctypes",
    ],
)

sandwich_variant(
    name = "openssl3",
    srcs = _SANDWICH_SRCS,
    crate_features = ["openssl3"],
    generate_ffi = True,
    rustc_flags = [
        "-W",
        "missing_docs",
    ],
    visibility = ["//visibility:public"],
    deps = [":openssl3_bindgen"] + _SANDWICH_PROTOBUF_DEPS,
)

rust_static_library(
    name = "sandwich_openssl3_ffi_static",
    srcs = _SANDWICH_SRCS,
    crate_features = [
        "ffi",
        "openssl3",
        "tunnel",
    ],
    crate_name = "sandwich_openssl3",
    visibility = ["//visibility:public"],
    deps = [":openssl3_bindgen"] + _SANDWICH_PROTOBUF_DEPS,
)

rust_shared_library(
    name = "sandwich_openssl3_ffi_shared",
    srcs = _SANDWICH_SRCS,
    crate_features = [
        "ffi",
        "openssl3",
        "tunnel",
    ],
    crate_name = "sandwich_openssl3",
    visibility = ["//visibility:public"],
    deps = [":openssl3_bindgen"] + _SANDWICH_PROTOBUF_DEPS,
)

######################################
### END OpenSSL 3 related rules.   ###
######################################

######################################
### BEGIN Sandwich "full" variant  ###
###                                ###
### The "full" variant supports    ###
### OpenSSL 1.1.1 and BoringSSL    ###
######################################

# Dependencies for the Sandwich "full" variant.
_SANDWICH_FULL_VARIANT_DEPS = [
    ":boringssl_bindgen",
    ":openssl1_1_1_bindgen",
    ":openssl3_bindgen",
] + _SANDWICH_PROTOBUF_DEPS

sandwich_variant(
    name = "full",
    srcs = _SANDWICH_SRCS,
    crate_features = [
        "boringssl",
        "openssl1_1_1",
        "openssl3",
        "tunnel",
        "tracer",
    ],
    generate_doc = True,
    generate_ffi = True,
    proc_macro_deps = ["@crate_index//:async-trait"],
    rustc_flags = [
        "-W",
        "missing_docs",
    ],
    visibility = [
        "//visibility:public",
    ],
    deps = _SANDWICH_FULL_VARIANT_DEPS,
)

rust_static_library(
    name = "sandwich_full_ffi_static",
    srcs = _SANDWICH_SRCS,
    crate_features = [
        "boringssl",
        "ffi",
        "openssl1_1_1",
        "openssl3",
        "tunnel",
        "tracer",
    ],
    crate_name = "sandwich_full",
    proc_macro_deps = ["@crate_index//:async-trait"],
    visibility = ["//visibility:public"],
    deps = _SANDWICH_FULL_VARIANT_DEPS,
)

rust_shared_library(
    name = "sandwich_full_ffi_shared",
    srcs = _SANDWICH_SRCS,
    crate_features = [
        "boringssl",
        "ffi",
        "openssl1_1_1",
        "openssl3",
        "tunnel",
        "tracer",
    ],
    crate_name = "sandwich_full",
    proc_macro_deps = ["@crate_index//:async-trait"],
    visibility = ["//visibility:public"],
    deps = _SANDWICH_FULL_VARIANT_DEPS,
)

sandwich_variant(
    name = "full+turbo",
    srcs = _SANDWICH_SRCS,
    crate_features = [
        "boringssl",
        "openssl1_1_1",
        "openssl3",
        "turbo",
        "tracer",
    ],
    generate_doc = True,
    generate_ffi = True,
    proc_macro_deps = ["@crate_index//:async-trait"],
    rustc_flags = [
        "-W",
        "missing_docs",
    ],
    visibility = [
        "//visibility:public",
    ],
    deps = _SANDWICH_FULL_VARIANT_DEPS + _SANDWICH_TURBO_DEPS,
)

rust_static_library(
    name = "sandwich_full+turbo_ffi_static",
    srcs = _SANDWICH_SRCS,
    crate_features = [
        "boringssl",
        "ffi",
        "openssl1_1_1",
        "openssl3",
        "tunnel",
        "turbo",
        "tracer",
    ],
    crate_name = "sandwich_full_turbo",
    proc_macro_deps = ["@crate_index//:async-trait"],
    visibility = ["//visibility:public"],
    deps = _SANDWICH_FULL_VARIANT_DEPS + _SANDWICH_TURBO_DEPS,
)

rust_shared_library(
    name = "sandwich_full+turbo_ffi_shared",
    srcs = _SANDWICH_SRCS,
    crate_features = [
        "boringssl",
        "ffi",
        "openssl1_1_1",
        "openssl3",
        "tunnel",
        "turbo",
        "tracer",
    ],
    crate_name = "sandwich_full_turbo",
    proc_macro_deps = ["@crate_index//:async-trait"],
    visibility = ["//visibility:public"],
    deps = _SANDWICH_FULL_VARIANT_DEPS + _SANDWICH_TURBO_DEPS,
)

mkdocs_tree(
    name = "mkdocs",
    srcs = [":sandwich_full_ffi_doc"],
    path = "rust_api",
    visibility = ["//docs:__subpackages__"],
)

build_test(
    name = "build_test",
    targets = [
        ":sandwich_full_ffi_doc",
        ":sandwich_full_ffi_clippy",
    ],
)

alias(
    name = "protobuf",
    actual = "@crate_index//:protobuf",
    visibility = ["//visibility:public"],
)
